package com.qkl.xiatang.app.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.qkl.xiatang.app.dto.BusinessDTO;
import com.qkl.xiatang.app.dto.PageOutDTO;
import com.qkl.xiatang.app.dto.device.SensorDataListDTO;
import com.qkl.xiatang.app.dto.device.SensorDataListOutDTO;
import com.qkl.xiatang.app.dto.feed.FeedVO;
import com.qkl.xiatang.app.dto.message.*;
import com.qkl.xiatang.app.dto.pond.QueryPondNamesOutDTO;
import com.qkl.xiatang.app.dto.task.TaskTimeVO;
import com.qkl.xiatang.app.entity.feed.*;
import com.qkl.xiatang.app.entity.message.*;
import com.qkl.xiatang.app.entity.pond.PondEntity;
import com.qkl.xiatang.app.entity.user.AppUserInfo;
import com.qkl.xiatang.app.mapper.*;
import com.qkl.xiatang.app.service.config.FeedAllocConfigService;
import com.qkl.xiatang.app.utils.*;
import com.qkl.xiatang.app.utils.appenum.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.text.SimpleDateFormat;
import java.util.*;

@Slf4j
@Service
public class MessageService {

    @Autowired
    private MessageMapper messageMapper;

    @Autowired
    private FeedManagerMapper feedMapper;

    @Autowired
    private FeedManagerService feedManagerService;

    @Autowired
    private MessageUserMapper messageUserMapper;

    @Autowired
    private ConfigService configService;

    @Autowired
    private MessagePushService messagePushService;

    @Autowired
    private MessageTypeMapper messageTypeMapper;

    @Autowired
    private PondManagerMapper pondManagerMapper;

    @Autowired
    private AppThreadPoolService appThreadPool;

    @Autowired
    private PondNamesService pondNamesService;

    @Autowired
    private TaskTimeService taskTimeService;

    @Autowired
    private MessageDetailMapper messageDetailMapper;

    @Autowired
    private MessageDetailService messageDetailService;

    @Autowired
    private FeedAllocConfigMapper feedAllocConfigMapper;

    @Autowired
    private MessageQueryTimeMapper messageQueryTimeMapper;

    @Autowired
    private FeedAllocMapper feedAllocMapper;

    @Autowired
    private MessageTypeSubMapper messageTypeSubMapper;

    @Autowired
    private PondGroupMsgService pondGroupMsgService;

    @Autowired
    private FeedAllocBaseService feedAllocBaseService;

    @Autowired
    private FeedAllocConfigService feedAllocConfigService;

    private static String fmtAllocDate(Date allocDate){
        return MsgUtils.fmtAllocDate(allocDate);
    }

    /**
     * 是否存在配料
     * @param companyId
     * @param templateId
     * @param allocDate
     * @return
     */
    public boolean existsAllocFeed(String companyId,String templateId,Date allocDate){
        return feedAllocBaseService.existsAllocFeed(companyId,templateId,allocDate);
    }

    public void sendNotAllocFeedMessage(String companyId,String templateId, Date allocDate){
        long delayMinute = AppUtils.parseInt(configService.getConfigureValue("notice_not_alloc_feed_time"));
        if(delayMinute < 1){
            log.info("延迟时间非法 ======delayMinute={}",delayMinute);
            return;
        }
        appThreadPool.scheduleMinute(()->{
            List<MessageSendVO> sendVOList = feedAllocBaseService.queryNotAllocMessage(companyId,templateId,allocDate);
            if(ObjectUtils.isNotEmpty(sendVOList)){
                for (MessageSendVO sendVO : sendVOList){
                    //sendVO.setMessage(feedAllocConfigService.getTemplateName(companyId,templateId));
                    sendMessage(sendVO);
                }
            }
        },delayMinute);
    }

    /**
     * 发送取消动多个动保任务消息
     * @param cancelZooList
     */
    public void sendCancelZooMessage(List<CancelZooMessageDTO> cancelZooList){
        if(ObjectUtils.isEmpty(cancelZooList)){
            return ;
        }
        String companyId = AppSessionUtils.getCompanyId();
        String userName = AppSessionUtils.getUserName();
        String userId = AppSessionUtils.getUserId();
        for (CancelZooMessageDTO cancelZooDTO : cancelZooList ){
            Date allocDate = cancelZooDTO.getAllocDate();
            List<QueryPondNamesOutDTO> pondNamesList = cancelZooDTO.getPondNamesList();
            if(ObjectUtils.isEmpty(pondNamesList)){
                continue;
            }
            for (QueryPondNamesOutDTO pondNamesDTO : pondNamesList){
                pondNamesDTO.setUserName(userName);
                pondNamesDTO.setUserId(userId);
            }
            MessageTypeEnum typeEnum = MessageTypeEnum.WEIGH_ZOO;
            FeedVO feedVO = messageDetailService.queryFeedVoPondNames(pondNamesList);
            int subType = MessageTypeSubEnum.WEIGH_ZOO_CANCEL.getSubType();
            String title = MessageTypeSubEnum.WEIGH_ZOO_CANCEL.getName();
            String titleSub = AppDateUtils.formatMsgDate(allocDate);
            String content = QueryPondNamesOutDTO.toMessage(pondNamesList,feedVO);
            MessageSendVO sendVO = MessageSendVO.create(companyId,title,titleSub,typeEnum, subType,allocDate,content);
            sendVO.addDetailList(pondNamesList,feedVO);
            sendVO.setImageList(feedVO.getImageList());
            this.sendMessageAsync(sendVO);

            ZooAllocDetailEntity task = new ZooAllocDetailEntity();
            task.setAllocDate(allocDate);
            task.setCompanyId(companyId);
            task.setStatus(FeedAllocStatusEnum.CANCEL.getStatus());
            this._sendFeedMessageByFeed(task);
        }
    }
    public List<CancelZooMessageDTO> queryCancelZooMessage(List<String> taskGroupIdList){
        List<Date> allocDateList = feedAllocMapper.cancelZooAllocDate(taskGroupIdList);
        if(ObjectUtils.isEmpty(allocDateList)){
            return new ArrayList<>();
        }
        List<CancelZooMessageDTO> list = new ArrayList<>();
        String companyId = AppSessionUtils.getCompanyId();
        for(Date allocDate : allocDateList){
            CancelZooMessageDTO dto = new CancelZooMessageDTO();
            dto.setAllocDate(allocDate);
            dto.setPondNamesList(pondNamesService.queryUnfeededZooPondNames(companyId,allocDate));
            list.add(dto);
        }
        return list;
    }

    /**
     * 发送取消多个喂料任务消息
     * @param serialNo
     * @param allocDate
     * @param pondNamesList
     */
    public void sendCancelFeedListMessage(Integer serialNo,Date allocDate,List<QueryPondNamesOutDTO> pondNamesList){
        String companyId = AppSessionUtils.getCompanyId();
        String userName = AppSessionUtils.getUserName();
        String userId = AppSessionUtils.getUserId();
        log.info("========sendCancelFeedListMessage.pondNamesList={}",pondNamesList);
        if(ObjectUtils.isEmpty(pondNamesList)){
            return;
        }
        for (QueryPondNamesOutDTO pondNamesDTO : pondNamesList){
            pondNamesDTO.setUserName(userName);
            pondNamesDTO.setUserId(userId);
        }

        String serialName = this.querySerialName(companyId,serialNo);
        MessageTypeEnum typeEnum = MessageTypeEnum.WEIGH_FEED;
        FeedVO feedVO = messageDetailService.queryFeedVoPondNames(pondNamesList);
        String title = MessageTypeSubEnum.WEIGH_FEED_CANCEL.getName();
        int subType = MessageTypeSubEnum.WEIGH_FEED_CANCEL.getSubType();
        String titleSub = AppDateUtils.formatMsgDate(allocDate) + serialName;
        String content = QueryPondNamesOutDTO.toMessage(pondNamesList,feedVO);
        MessageSendVO sendVO = MessageSendVO.create(companyId,title,titleSub,typeEnum,subType,allocDate,content);
        sendVO.addDetailList(pondNamesList,feedVO);
        sendVO.setImageList(feedVO.getImageList());
        this.sendMessageAsync(sendVO);

        FeedAllocDetailEntity task = new FeedAllocDetailEntity();
        task.setAllocDate(allocDate);
        task.setCompanyId(companyId);
        task.setSerialNo(serialNo);
        task.setName(serialName);
        task.setStatus(FeedAllocStatusEnum.CANCEL.getStatus());
        this._sendFeedMessageByFeed(task);
    }

    public void sendCancelFeedListMessage(AppUserInfo userInfo,List<FeedAllocDetailEntity> taskList,List<PondEntity>  pondMsgList,List<FeedMsgDTO>  feedMsgList){
        if(null == userInfo || ObjectUtils.isEmpty(taskList) || ObjectUtils.isEmpty(pondMsgList) || ObjectUtils.isEmpty(feedMsgList) ){
            return;
        }
        String companyId = userInfo.getCompanyId();
        String userName = userInfo.getName();
        Date allocDate = taskList.get(0).getAllocDate();
        List<String> pondIdList = new ArrayList<>();
        List<String> pondNames = new ArrayList<>();
        if(ObjectUtils.isNotEmpty(pondMsgList)){
            for (PondEntity pond : pondMsgList){
                pondIdList.add(pond.getId());
                pondNames.add(pond.getName());
            }
        }
        MessageTypeEnum typeEnum = MessageTypeEnum.WEIGH_FEED;
        String title = MessageTypeSubEnum.WEIGH_FEED_CANCEL.getName();
        int subType = MessageTypeSubEnum.WEIGH_FEED_CANCEL.getSubType();
        String titleSub = MsgUtils.formatTitleMessage(taskList);
        MessageSendVO sendVO = MessageSendVO.create(companyId,title,titleSub,typeEnum,subType,allocDate,"");
        sendVO.addDetailList(userName,pondNames,feedMsgList);
        sendVO.setPondIdList(pondIdList);
        this.sendMessageAsync(sendVO);
    }

    /**
     * 发送取消任务消息
     * @param detailEntity
     */
    public void  sendCancelTaskMessage(AllocBaseEntity detailEntity){
        BusinessDTO<Object> businessDTO = _sendCancelTaskMessage(detailEntity);
        log.info("===========sendCancelTaskMessage.businessDTO={}",businessDTO);
    }
    private BusinessDTO<Object> _sendCancelTaskMessage(AllocBaseEntity task){
        String companyId = task.getCompanyId();
        String userName = task.getFeedUserName();
        String pondId = task.getPondId();
        Date allocDate = task.getAllocDate();
        MessageTypeEnum typeEnum = null;
        String serialName = "";
        MessageTypeSubEnum subEnum = MessageTypeSubEnum.ZOO_CANCEL;;
        if(task instanceof  FeedAllocDetailEntity){
            serialName = ((FeedAllocDetailEntity)task).getName() + " ";
            typeEnum = MessageTypeEnum.FEED;
            subEnum = MessageTypeSubEnum.FEED_CANCEL;
        }else {
            typeEnum = MessageTypeEnum.ZOO;
        }
        String line = Constants.ENTER_LINE;
        FeedVO feedVO = messageDetailService.queryFeedVoMessage(task.getFeedId());
        List<String> pondNameList = pondNamesService.queryPondNames(pondId);
        int subType = subEnum.getSubType();
        String title = subEnum.getName();
        String titleSub = fmtAllocDate(allocDate) + " " + serialName;
        String content = MsgUtils.formatMessage(userName) + line + MsgUtils.formatPondNames(pondNameList) + line + "塘";
        MessageSendVO sendVO = MessageSendVO.create(companyId,title,titleSub,typeEnum,subType,allocDate,content);
        sendVO.setImageList(feedVO.getImageList());
        sendVO.addDetailList(userName,pondNameList,feedVO.getFeedMsgList());
        sendVO.setPondIdList(new ArrayList<>());
        sendVO.getPondIdList().add(pondId);

        BusinessDTO<Object> businessDTO = this.sendMessageAsync(sendVO);
        this._sendFeedMessageByFeed(task);
        return businessDTO;
    }


    /**
     *发送打动保消息，完成动保称料全部任务
     * @param companyId
     * @param userName
     * @param messageMap 打动保日期 yyyy.mm.dd
     */
    public void  sendFeedMessageByWeigh(String companyId, String userName, Map<String,List<String>> messageMap ){
        Set<Map.Entry<String,List<String>>> entrySet = messageMap.entrySet();
        for(Map.Entry<String,List<String>> entry : entrySet ){
            Date allocDate = AppDateUtils.yyyymmddTodate(entry.getKey());
            ZooAllocDetailEntity messageTask = new ZooAllocDetailEntity();
            messageTask.setCompanyId(companyId);
            messageTask.setWeighUserName(userName);
            messageTask.setAllocDate(allocDate);
            messageTask.setFeedId("");

            _sendFeedMessageByWeigh(messageTask);

        }
    }

    /**
     * 发送喂饲料或打动保消息，称料时
     * @param detailEntity
     */
    public void  sendFeedMessageByWeigh(AllocBaseEntity detailEntity){
        List<AllocBaseEntity> taskList = new ArrayList<>();
        taskList.add(detailEntity);
        this.sendFeedMessageByWeigh(taskList);
    }
    public void  sendFeedMessageByWeigh(List<? extends AllocBaseEntity> taskList){
        _sendFeedMessageByWeigh(taskList);
    }
    private void  _sendFeedMessageByWeigh(List<? extends AllocBaseEntity> taskList){
        for (AllocBaseEntity task : taskList){
            log.info("===========sendFeedMessageByWeigh.businessDTO={}",_sendFeedMessageByWeigh(task));
        }
    }
    private BusinessDTO<Object> _sendFeedMessageByWeigh(AllocBaseEntity task){
        boolean isFeed = false;
        if(task instanceof  FeedAllocDetailEntity){
            isFeed = true;
        }
        MessageTypeEnum typeEnum = isFeed? MessageTypeEnum.FEED : MessageTypeEnum.ZOO;
        MessageTypeSubEnum subEnum = isFeed? MessageTypeSubEnum.FEED_WEIGH_FINISH: MessageTypeSubEnum.ZOO_WEIGH_FINISH;
        int subType = subEnum.getSubType();
        String serialName = "";
        TaskTimeVO taskTimeVO = taskTimeService.queryWeighTaskTime(task);
        if(isFeed){
            FeedAllocDetailEntity feedTask = (FeedAllocDetailEntity)task;
            serialName = feedTask.getName() + " ";
        }

        log.info("=====sendFeedMessageByWeigh.taskTimeVO={}",taskTimeVO);
        String companyId = task.getCompanyId();
        //String line = Constants.ENTER_LINE;
        if(taskTimeVO.finishAll()){
            List<QueryPondNamesOutDTO>  pondNamesList = pondNamesService.queryWeighPondNames(task);
            FeedVO feedVO = messageDetailService.queryFeedVoPondNames(pondNamesList);

            String title = subEnum.getName();
            String titleSub = AppDateUtils.formatMsgDate(task.getAllocDate()) + serialName;
            String message = taskTimeVO.showWeighTimeRange()  + " " + "称完";
            String content = QueryPondNamesOutDTO.toMessage(pondNamesList,"");

            MessageSendVO sendVO = MessageSendVO.create(companyId,title,titleSub,typeEnum,subType,task.getAllocDate(),content);
            sendVO.setMessage(message);
            sendVO.addDetailList(pondNamesList,feedVO);
            sendVO.setImageList(feedVO.getImageList());
            this.sendMessageAsync(sendVO);
        }else if(taskTimeVO.finishFirst()){
        }
        return null;
    }

    /**
     * 发送喂饲料或打动保消息，喂料时
     * @param detailEntity
     */
    public void  sendFeedMessageByFeed(AllocBaseEntity detailEntity){
        BusinessDTO<Object>  businessDTO = _sendFeedMessageByFeed(detailEntity);
        log.info("==========sendFeedMessageByFeed.businessDTO={}",businessDTO);
    }
    private BusinessDTO<Object>   _sendFeedMessageByFeed(AllocBaseEntity task){
        boolean isFeed = false;
        if(task instanceof  FeedAllocDetailEntity){
            isFeed = true;
        }
        //MessageTypeEnum typeEnum = isFeed? MessageTypeEnum.FEED : MessageTypeEnum.ZOO;
        MessageTypeEnum typeEnum = isFeed? MessageTypeEnum.CHECK : MessageTypeEnum.ZOO;//发给查料台 update by 2024.04.24
        String serialName = "";
        TaskTimeVO taskTimeVO = taskTimeService.queryFeedTaskTime(task);
        if(isFeed){
            FeedAllocDetailEntity feedTask = (FeedAllocDetailEntity)task;
            serialName = feedTask.getName() + " ";
        }
        log.info("=====sendFeedMessageByFeed.taskTimeVO={}",taskTimeVO);
        String companyId = task.getCompanyId();
        String userName = task.getFeedUserName();
        if(taskTimeVO.finishAll()){
            MessageTypeSubEnum subEnum = isFeed? MessageTypeSubEnum.FEED_END:MessageTypeSubEnum.ZOO_FINISH;
            int subType = subEnum.getSubType();
            List<QueryPondNamesOutDTO>  pondNamesList = pondNamesService.queryFeedPondNames(task);
            FeedVO feedVO = messageDetailService.queryFeedVoPondNames(pondNamesList);
            String title = subEnum.getName();
            String titleSub = AppDateUtils.formatMsgDate(task.getAllocDate()) + serialName;
            String message = taskTimeVO.showTimeRange() + " 投完";
            String content = QueryPondNamesOutDTO.toMessage(pondNamesList);
            MessageSendVO sendVO = MessageSendVO.create(companyId,title,titleSub,typeEnum,subType,task.getAllocDate(),content);
            sendVO.setMessage(message);
            sendVO.addDetailList(pondNamesList,feedVO);
            sendVO.setImageList(feedVO.getImageList());
            return this.sendMessageAsync(sendVO);

        }else if(taskTimeVO.finishFirst() && !FeedAllocStatusEnum.cancelStatus(task.getStatus())){

            /** 首次喂料不发送  update by 2024.04.24
            MessageTypeSubEnum subEnum = isFeed? MessageTypeSubEnum.FEED_START:MessageTypeSubEnum.ZOO_START;
            int subType = subEnum.getSubType();
            List<String> pondNames = pondNamesService.queryPondNames(task.getPondId());
            FeedVO feedVO = messageDetailService.queryFeedVoMessage(task.getFeedId());
            String title = subEnum.getName();
            String titleSub = AppDateUtils.formatMsgDate(task.getAllocDate()) + serialName;
            String content = "[" + userName + "]" + Constants.ENTER_LINE + MsgUtils.formatPondNames(pondNames);
            MessageSendVO sendVO = MessageSendVO.create(companyId,title,titleSub,typeEnum,subType,task.getAllocDate(),content);
            sendVO.addDetailList(userName,pondNames,feedVO.getFeedMsgList());
            sendVO.setImageList(feedVO.getImageList());
            sendVO.setPondIdList(new ArrayList<>());
            sendVO.getPondIdList().add(task.getPondId());
            return this.sendMessageAsync(sendVO);
             **/
        }
        return null;
    }

    /**
     * 发送查料台消息
     * @param task
     * @param isCheck true查料台发磅，false 喂料发送
     */
    public void sendCheckMessage(FeedAllocDetailEntity task,boolean isCheck){
        _sendCheckMessage(task,isCheck);
        /**
        appThreadPool.execute(()->{
            _sendCheckMessage(task,isCheck);
        });
         **/
    }
    private BusinessDTO<Object>   _sendCheckMessage(FeedAllocDetailEntity task,boolean isCheck){
        String companyId = task.getCompanyId();
        String line = Constants.ENTER_LINE;
        MessageTypeEnum typeEnum = MessageTypeEnum.CHECK;
        String serialName = task.getName();
        String content = "";
        TaskTimeVO taskTimeVO = null;
        if( !isCheck ){
            taskTimeVO = taskTimeService.queryFeedFeedTaskTime(companyId,task.getAllocDate(),task.getSerialNo(),null);
            if(taskTimeVO.finishFirst()){
                int subType = MessageTypeSubEnum.CHECK_FEED_START.getSubType();
                FeedVO feedVO = messageDetailService.queryFeedVoMessage(task.getFeedId());
                List<String> pondNames = pondNamesService.queryPondNames(task.getPondId());
                String title = MessageTypeSubEnum.CHECK_FEED_START.getName();
                String titleSub = AppDateUtils.formatMsgDate(task.getAllocDate())  + " " + serialName;
                String message = MsgUtils.formatMessage(task.getFeedUserName()) + "开始投放，注意查料台";
                content = message + line + MsgUtils.formatPondNames(pondNames) + line + "塘";
                MessageSendVO sendVO = MessageSendVO.create(companyId,title,titleSub,typeEnum,subType,task.getAllocDate(),content);
                //sendVO.setMessage(message);
                sendVO.addDetailList(task.getFeedUserName(),pondNames,feedVO.getFeedMsgList());
                sendVO.setImageList(feedVO.getImageList());
                sendVO.setPondIdList(new ArrayList<>());
                sendVO.getPondIdList().add(task.getPondId());
                return this.sendMessageAsync(sendVO);
            }
        }else {
            taskTimeVO = taskTimeService.queryFeedCheckTaskTime(companyId,task.getAllocDate(),task.getSerialNo(),null);
            if(taskTimeVO.finishAll()){
                if(null == task.getCheckTime()) {
                    int subType = MessageTypeSubEnum.CHECK_FINISH.getSubType();
                    List<QueryPondNamesOutDTO> pondNamesList = pondNamesService.queryCheckPondNames(companyId, task.getAllocDate(), task.getSerialNo());
                    FeedVO feedVO = messageDetailService.queryFeedVoPondNames(pondNamesList);
                    String title = MessageTypeSubEnum.CHECK_FINISH.getName();
                    String titleSub = AppDateUtils.formatMsgDate(task.getAllocDate()) + " " + serialName;
                    String message = taskTimeVO.showTimeRange() + " 查完";
                    content = QueryPondNamesOutDTO.toMessage(pondNamesList);
                    MessageSendVO sendVO = MessageSendVO.create(companyId, title, titleSub, typeEnum, subType, task.getAllocDate(), content);
                    sendVO.setMessage(message);
                    sendVO.addDetailList(pondNamesList, feedVO);
                    sendVO.setImageList(feedVO.getImageList());
                    return this.sendMessageAsync(sendVO);
                }
            }else if(taskTimeVO.finishFirst()){
                int subType = MessageTypeSubEnum.CHECK_START.getSubType();
                FeedVO feedVO = messageDetailService.queryFeedVoMessage(task.getFeedId());
                List<String> pondNames = pondNamesService.queryPondNames(task.getPondId());
                String title = MessageTypeSubEnum.CHECK_START.getName();
                String titleSub = AppDateUtils.formatMsgDate(task.getAllocDate())  + " " + serialName;
                String message = MsgUtils.formatMessage(task.getCheckUserName()) + "开始查料台";
                content = message + line + MsgUtils.formatPondNames(pondNames) + line + "塘";
                MessageSendVO sendVO = MessageSendVO.create(companyId,title,titleSub,typeEnum,subType,task.getAllocDate(),content);
                //sendVO.setMessage(message);
                sendVO.addDetailList(task.getCheckUserName(),pondNames,feedVO.getFeedMsgList());
                sendVO.setImageList(feedVO.getImageList());
                return this.sendMessageAsync(sendVO);
            }
        }
        return null;
    }


    /**
     * 发送称料消息
     * @param messageDTO
     */
    public void sendWeighMessage(SendWeighMessageDTO messageDTO){
        appThreadPool.execute(()->{
            BusinessDTO<Object> businessDTO = _sendWeighMessage(messageDTO);
            log.info("===========sendWeighMessage.businessDTO={}",businessDTO);
        });
    }

    private BusinessDTO<Object> _sendWeighMessage(SendWeighMessageDTO messageDTO){
        List<String> pondIdList = messageDTO.getPondIdList();
        MessageTypeEnum typeEnum = messageDTO.getTypeEnum();
        List<String> feedIdList = messageDTO.getFeedIdList();
        Date allocDate = messageDTO.getAllocDate();
        String companyId = messageDTO.getCompanyId();
        String userName = messageDTO.getUserName();
        String templateId = messageDTO.getTemplateId();

        List<String> pondNames = messageDetailService.queryPondNamesMessage(pondIdList);
        if(ObjectUtils.isEmpty(pondNames)){
            return BusinessDTO.failBusiness("无效塘号");
        }
        boolean isWeighFeed = (typeEnum == MessageTypeEnum.WEIGH_FEED) ? true:false;

        FeedVO feedVO = messageDetailService.queryFeedVoMessage(feedIdList);

        MessageTypeSubEnum subEnum = isWeighFeed? MessageTypeSubEnum.WEIGH_FEED_FINISH:MessageTypeSubEnum.WEIGH_ZOO_ALLOC;
        int subType = subEnum.getSubType();
        String title = subEnum.getName();
        String titleSub = feedAllocConfigService.formatMealNames(templateId,allocDate);

        String line = Constants.ENTER_LINE;
        StringBuffer stringBuffer = new StringBuffer();
        stringBuffer.append( "[" + userName + "]" + line);
        stringBuffer.append(MsgUtils.formatPondNames(pondNames)  + line + "塘");
        String content = stringBuffer.toString();

        MessageSendVO sendVO = MessageSendVO.create(companyId,title,titleSub,typeEnum,subType,allocDate,content);
        sendVO.addDetailList(userName,pondNames,feedVO.getFeedMsgList());
        sendVO.setImageList(feedVO.getImageList());
        sendVO.setPondIdList(pondIdList);

        return this.sendMessage(sendVO);
    }


    public BusinessDTO<Object> sendMessageAsync(MessageSendVO sendVO){
        appThreadPool.execute(()->{
            BusinessDTO<Object> businessDTO = sendMessage(sendVO);
            log.info("===========sendMessageAsync.businessDTO={}",businessDTO);
        });
        return BusinessDTO.sucessBusiness(new HashMap<>());
    }

    public BusinessDTO<Object> sendMessage(MessageSendVO sendVO){
        String companyId = sendVO.getCompanyId();
        MessageEntity entity = sendVO.toMessageEntity();

        List<String> userIdList = pondGroupMsgService.queryPondGroupUsers(entity);
        if(ObjectUtils.isNotEmpty(userIdList)){
            entity.setFlag(1);
        }
        this.addMessage(entity);
        this.initMessageUser(entity.getId(),userIdList);
        MessagePushUserDTO pushUserDTO = this.queryMessagePushDevice(companyId,entity.getSubType(),entity.getId());
        messagePushService.pushMessage(sendVO.getTitle(),sendVO.getTitleSub(),pushUserDTO,sendVO.getType());
        return BusinessDTO.sucessBusiness(entity);
    }


    public void addMessage(MessageEntity entity){
        String companyId = AppSessionUtils.getCompanyId();
        if(StringUtils.isEmpty(entity.getCompanyId()) && StringUtils.isNotEmpty(companyId)){
            entity.setCompanyId(companyId);
        }
        if(null == entity.getCreateTime()){
            entity.setCreateTime(new Date());
        }
        if(null == entity.getMsgDate()){
            entity.setMsgDate(AppUtils.todayYyyyMMdd());
        }
        messageMapper.insert(entity);
        MessageDetailEntity detailEntity = new MessageDetailEntity();
        detailEntity.setMessageId(entity.getId());
        detailEntity.setContent(entity.getMessageDetail());
        messageDetailMapper.insert(detailEntity);
    }

    /**
     * 饲料库存警告消息
     * @param companyId
     * @param warnList
     */
    public void addStockWarnMessage(String companyId,List<FeedEntity>  warnList){
        if(ObjectUtils.isEmpty(warnList)){
            return;
        }
        MessageTypeEnum typeEnum = MessageTypeEnum.ADMIN;
        //String title = typeEnum.getName();
        Date msgDate = AppUtils.todayYyyyMMdd();
        List<MessageSendVO> messageList = new ArrayList<>();
        // 动保 巧科粒牌[光合细菌]库存30斤，少于100斤!
        for (FeedEntity feedEntity : warnList){
            String taskName = "饲料 ";
            if(feedEntity.typeZoo()){
                taskName = "动保 ";
            }
            String title = taskName + MessageTypeSubEnum.ADMIN_STOCK.getName();
            String titleSub = MsgUtils.formatMessage(feedEntity.getName()) + "库存" + feedEntity.getStock() + "," + "少于" + feedEntity.getWarnValue() + "斤!";
            //int subType = feedEntity.getId().hashCode();
            int subType = MessageTypeSubEnum.ADMIN_STOCK.getSubType();
            Integer threeType = feedEntity.getId().hashCode();
            MessageSendVO sendVO = MessageSendVO.create(companyId,title,titleSub,typeEnum,subType,msgDate,"");
            sendVO.setThreeType(threeType);
            sendVO.setImageList(new ArrayList<>());
            sendVO.getImageList().add(feedEntity.getImage());
            sendVO.addDetailList(feedEntity);
            messageList.add(sendVO);
        }
        this.addMessageList(companyId,typeEnum,msgDate,messageList);
    }


    /**
     * 设备数据异常消息
     * @param businessDTO
     */
    public void addMessage(BusinessDTO<SensorDataListOutDTO> businessDTO){
        String companyId = AppSessionUtils.getCompanyId();
        appThreadPool.execute(()->{
            addMessage11(companyId,businessDTO);
        });
    }
    private void addMessage11(String companyId,BusinessDTO<SensorDataListOutDTO> businessDTO){
        MessageTypeEnum typeEnum = MessageTypeEnum.ADMIN;
        Date msgDate = AppUtils.todayYyyyMMdd();
        //String title = typeEnum.getName();
        List<MessageSendVO> messageList = new ArrayList<>();
        if(!businessDTO.isSucess()){
            int subType = MessageTypeSubEnum.ADMIN_SENSOR_OFF_LINE.getSubType();
            String title = MessageTypeSubEnum.ADMIN_SENSOR_OFF_LINE.getName();
            String titleSub = title;
            MessageSendVO sendVO = MessageSendVO.create(companyId,title,titleSub,typeEnum,subType,msgDate,"");
            sendVO.setThreeType(businessDTO.getCode());
            messageList.add(sendVO);

        }else if(ObjectUtils.isNotEmpty(businessDTO.getBusinessObject().getList())){
            List<SensorDataListDTO> list = businessDTO.getBusinessObject().getList();
            for(SensorDataListDTO dto : list){
                if(dto.getIsNormal()){
                    continue;
                }
                String title = dto.getTypeName() + dto.getValue() + "异常";
                String titleSub = "正常为:" + dto.getNormal();
                Integer subType = MessageTypeSubEnum.ADMIN_SENSOR.getSubType();
                Integer threeType = 100 + dto.getType();
                MessageSendVO sendVO = MessageSendVO.create(companyId,title,titleSub,typeEnum,subType,msgDate,"");
                sendVO.setThreeType(threeType);
                messageList.add(sendVO);
            }
        }
        this.addMessageList(companyId,typeEnum,msgDate,messageList);
    }

    private void addMessageList(String companyId,MessageTypeEnum typeEnum,Date msgDate,List<MessageSendVO> messageList){
        String title = typeEnum.getName();
        if(ObjectUtils.isNotEmpty(messageList)){
            for (MessageSendVO sendVO : messageList){
                if(this.isExistMessage(companyId,typeEnum.getType(),msgDate,sendVO.getThreeType())){
                    continue;
                }
                MessageEntity message = sendVO.toMessageEntity();
                MessagePushUserDTO pushUserDTO = this.queryMessagePushDevice(companyId,message.getSubType(),message.getId());
                this.addMessage(message);
                messagePushService.pushMessage(title,message.getContent(),pushUserDTO,typeEnum);
            }
        }
    }

    /**
     * 消息列表查询
     * @param indto
     * @return
     */
    public PageOutDTO<MessageListOutDTO> queryMessageList(MessageListInDTO indto){
        Date queryTime = getMessageQueryTime(AppSessionUtils.getCreateTime());
        indto.setQueryTime(queryTime);
        String messageTypeId = StringUtils.trimToEmpty(indto.getMessageTypeId());
        log.info("====queryMessageList.getIdentity={}",AppSessionUtils.getIdentity());
        List<Integer> typeList = MessageTypeUtils.toMessageList(AppSessionUtils.getIdentity());
        log.info("====queryMessageList1.typeList={}",typeList);
        if(StringUtils.isNotEmpty(messageTypeId)){
            MessageTypeEntity messageTypeEntity = messageTypeMapper.selectById(messageTypeId);
            if(null != messageTypeEntity){
                Integer type = messageTypeEntity.getType();
                if(messageTypeEntity.unreadType()){
                    indto.setUnreadType(100);
                }else if(typeList.contains(type)){
                    typeList.clear();
                    typeList.add(type);
                }else {
                    typeList.clear();
                }
            }
        }
        log.info("====queryMessageList2.typeList={}",typeList);
        indto.setTypeList(typeList);
        indto.setCompanyId(AppSessionUtils.getCompanyId());
        indto.setUserId(AppSessionUtils.getUserId());
        indto.checkParam();
        indto.setOnePageTime(this.getOnePageTime(indto.getPageIndex(),typeList));

        PageOutDTO<MessageListOutDTO> outDTO = new PageOutDTO<>();
        if(ObjectUtils.isNotEmpty(typeList)) {
            Integer totalRow = messageMapper.queryMessageListTotal(indto);
            totalRow = null == totalRow ? 0 : totalRow;
            outDTO.settingPage(indto, totalRow);
            if (totalRow > 0) {
                List<MessageListOutDTO> mapList = messageMapper.queryMessageList(indto);
                if (ObjectUtils.isNotEmpty(mapList)) {
                    for (MessageListOutDTO map : mapList) {
                        map.setImageList(AppUtils.stringToList(map.getImageListStrings()));
                        map.setImageListStrings("");
                    }
                }
                outDTO.setList(mapList);
            }
        }else {
            outDTO.settingPage(indto, 0);
        }

        if(ObjectUtils.isEmpty(outDTO.getList())){
            outDTO.setList(new ArrayList<>());
        }
        return outDTO;
    }

    /**
     * 消息详情
     * @param messageId
     * @return
     */
    public BusinessDTO<Object> queryMessageDetail(String messageId){
        MessageEntity messageEntity = messageMapper.selectById(messageId);
        if(null == messageEntity){
            return  BusinessDTO.failBusiness("查询无消息");
        }

        Map<String,Object> map = new HashMap<>();
        map.put("id",messageEntity.getId());
        map.put("image",messageEntity.getImage());
        map.put("createTime",new SimpleDateFormat("yyyy.MM.dd HH:mm:ss").format(messageEntity.getCreateTime()));
        map.put("title",messageEntity.getTitle());
        map.put("titleSub",messageEntity.getTitleSub());
        map.put("content",messageEntity.getContent());
        map.put("type",messageEntity.getType());
        map.put("subType",messageEntity.getSubType());
        map.put("isExpand",Boolean.valueOf(false));
        map.put("status",Integer.valueOf(1));//0 未读，1 已读
        map.put("imageList",AppUtils.stringToList(messageEntity.getImageList()));
        map.putAll( this.contentDetail(messageEntity));

        return BusinessDTO.sucessBusiness(map,"消息详情");
    }

    /**
     * 消息内容详情
     * @param messageId
     * @return
     */
    public BusinessDTO<Object> queryMessageContentDetail(String messageId){
        MessageEntity messageEntity = messageMapper.selectById(messageId);
        if(null == messageEntity){
            return  BusinessDTO.failBusiness("查询无消息");
        }
        return BusinessDTO.sucessBusiness(this.contentDetail(messageEntity),"消息内容详情");
    }

    private Map<String,Object> contentDetail(MessageEntity messageEntity){
        String messageId = messageEntity.getId();
        String userId = AppSessionUtils.getUserId();
        List<MessageUserEntity> messageUserList = messageUserMapper.selectList(new QueryWrapper<MessageUserEntity>().eq("message_id",messageId).eq("user_id",userId));
        MessageUserEntity messageUser = new MessageUserEntity();
        messageUser.setMessageId(messageId);
        messageUser.setUserId(userId);
        messageUser.setStatus(1);
        if(ObjectUtils.isEmpty(messageUserList)){
            messageUserMapper.insert(messageUser);
        }else {
            Date updateDate = new Date();
            for(MessageUserEntity entity : messageUserList){
                if(entity.unread()) {
                    messageUser.setId(entity.getId());
                    messageUser.setUpdateTime(updateDate);
                    messageUserMapper.updateById(messageUser);
                }
            }
        }

        List<MessageFormatDTO> list = null;
        MessageDetailEntity detailEntity = messageDetailService.queryMessageContentDetail(messageId);
        if(null != detailEntity && StringUtils.isNotEmpty(detailEntity.getContent())){
            list = JSON.parseArray(detailEntity.getContent(),MessageFormatDTO.class);
        }
        if(null == list){
            list = new ArrayList<>();
        }
        List<String> messageList = messageEntity.toMessageList();
        Map<String,Object> map = new HashMap<>();
        map.put("messageList",messageList);
        map.put("list",list);
        return map;
    }

    /**
     * 查询未读消息
     * @return
     */
    public BusinessDTO<Object> queryUnreadMessageTotal(){
        Date queryTime = getMessageQueryTime(AppSessionUtils.getCreateTime());
       Map<String,Object> map = new HashMap<>();
       map.put("unreadMessageTotal",this.queryUnreadMessageTotal0(MessageTypeUtils.toMessageList(AppSessionUtils.getIdentity()),queryTime));
       return BusinessDTO.sucessBusiness(map,"未读消息");
    }
    private Integer queryUnreadMessageTotal0(List<Integer> typeList,Date queryTime){
        Integer unreadMessageTotal = messageMapper.queryUnreadMessageTotal(AppSessionUtils.getCompanyId(),AppSessionUtils.getUserId(),typeList,queryTime);
        if(null == unreadMessageTotal){
            unreadMessageTotal = 0;
        }
        return unreadMessageTotal;
    }
    private Integer queryUnreadMessageTotal0(Integer type,Date queryTime){
        List<Integer> typeList = new ArrayList<>();
        typeList.add(type);
        return this.queryUnreadMessageTotal0(typeList,queryTime);
    }


    private List<MessageEntity> queryByTypeAndDate(String companyId ,Integer type,Date msgDate,Integer subType){
        QueryWrapper<MessageEntity> queryWrapper = new QueryWrapper<MessageEntity>().eq("type",type).eq("msg_date",msgDate);
        if(StringUtils.isNotEmpty(companyId)){
            queryWrapper.eq("company_id",companyId);
        }
        if(null != subType){
            queryWrapper.eq("three_type",subType);
        }
        return messageMapper.selectList(queryWrapper);
    }

    private boolean isExistMessage(String companyId ,Integer type,Date msgDate,Integer subType){
        return ObjectUtils.isNotEmpty(this.queryByTypeAndDate(companyId,type,msgDate,subType));
    }

    /**
     * 查询消息推送设备
     * @param companyId
     * @param subType
     * @param messageId
     * @return
     */
    public MessagePushUserDTO queryMessagePushDevice(String companyId, Integer subType,String messageId){
        MessagePushUserInDTO params = new MessagePushUserInDTO();
        params.setCompanyId(companyId);
        params.setSubType(subType);
        params.setMessageId(messageId);
        MessagePushUserDTO pushUserDTO = messageMapper.queryMessagePushDevice(params);
        if(null != pushUserDTO){
            pushUserDTO.setMessageId(messageId);
        }
        return pushUserDTO;
    }

    /**
     * 消息类型查询
     * @return
     */
    public BusinessDTO<Object> queryMessageTypeList(){
        Date queryTime = getMessageQueryTime(AppSessionUtils.getCreateTime());
        List<MessageTypeEntity> messageTypeList =  messageTypeMapper.selectList(null);
        if(ObjectUtils.isNotEmpty(messageTypeList)){
            List<Integer> userMessageTypeList = MessageTypeUtils.toMessageList(AppSessionUtils.getIdentity());
            for(MessageTypeEntity messageType : messageTypeList){
                if(messageType.unreadType()){
                    messageType.setUnreadCount(this.queryUnreadMessageTotal0(userMessageTypeList,queryTime));
                    continue;
                }
                Integer type = messageType.getType();
                if(userMessageTypeList.contains(type)){
                    messageType.setUnreadCount(this.queryUnreadMessageTotal0(type,queryTime));
                }
            }
        }
        Map<String,Object> map = new HashMap<>();
        map.put("messageTypeList",messageTypeList);
        return BusinessDTO.sucessBusiness(map,"消息类型查询");
    }

    /**
     * 消息接收设置
     * @param webDTO
     * @return
     */
    public BusinessDTO<Object> messageReceiveSet(MessageTypeSubWebDTO webDTO){
        log.info("======messageReceiveSet.webDTO={}",webDTO);
        List<MessageTypeSubDTO>  subTypeList = webDTO.getSubTypeList();
        String companyId = AppSessionUtils.getCompanyId();
        String userId = AppSessionUtils.getUserId();
        if(ObjectUtils.isEmpty(subTypeList)){
            return BusinessDTO.failBusiness("参数为空");
        }
        Set<Integer> subTypeSet = new TreeSet<>();
        Set<Integer> subTypeRefuseSet = new TreeSet<>();
        for(MessageTypeSubDTO subTypeDTO : subTypeList){
            Integer subType = subTypeDTO.getSubType();
            Integer status = subTypeDTO.getStatus();
            if(null == subType || null == status){
                continue;
            }
            subTypeSet.add(subType);
            if( subType != 0 && MsgUtils.subTypeNotReceive(status)){
                subTypeRefuseSet.add(subType);
            }
        }
        if( !subTypeSet.isEmpty()){
            messageTypeSubMapper.delete(new QueryWrapper<MessageTypeSubEntity>()
                                            .eq("company_id",companyId)
                                            .eq("user_id",userId)
                                            .in("sub_type",subTypeSet)
                                    );
        }
        if( !subTypeRefuseSet.isEmpty()){
            for(Integer subType : subTypeRefuseSet){
                MessageTypeSubEntity entity = new MessageTypeSubEntity();
                entity.setCompanyId(companyId);
                entity.setUserId(userId);
                entity.setSubType(subType);
                messageTypeSubMapper.insert(entity);
            }
        }
        return BusinessDTO.sucessBusiness(new HashMap<>(),"消息接收设置");
    }

    /**
     * 消息子类型查询
     * @return
     */
    public BusinessDTO<Object> queryMessageSubType(){
        String companyId = AppSessionUtils.getCompanyId();
        String userId = AppSessionUtils.getUserId();

        List<MessageTypeSubDTO>  subTypeList = new ArrayList<>();
        Map<Integer,MessageTypeSubEnum> allSubType = MessageTypeSubEnum.userSubType(AppSessionUtils.getUserAppInfo());
        List<MessageTypeSubEntity> refuseSubTypeList = messageTypeSubMapper.selectList(new QueryWrapper<MessageTypeSubEntity>()
                                                                                        .eq("company_id",companyId)
                                                                                        .eq("user_id",userId)
                                                                                        .eq("status",0)
                                                                                        );
        if(ObjectUtils.isNotEmpty(refuseSubTypeList)){
            for (MessageTypeSubEntity subTypeEntity : refuseSubTypeList){
                Integer subType = subTypeEntity.getSubType();
                MessageTypeSubEnum subEnum = MessageTypeSubEnum.getSubType(subType);
                if(null != subEnum){
                    subTypeList.add(MessageTypeSubDTO.create(subType,0,subEnum.getName()));
                    allSubType.remove(subType);
                }
            }
        }
        if(ObjectUtils.isNotEmpty(allSubType)){
            Set<Map.Entry<Integer, MessageTypeSubEnum>> set = allSubType.entrySet();
            for(Map.Entry<Integer, MessageTypeSubEnum> entry : set){
                MessageTypeSubEnum subEnum = entry.getValue();
                subTypeList.add(MessageTypeSubDTO.create(subEnum.getSubType(),1,subEnum.getName()));
            }
        }
        MessageTypeSubWebDTO webDTO = new MessageTypeSubWebDTO();
        webDTO.setSubTypeList(subTypeList);
        return BusinessDTO.sucessBusiness(webDTO,"消息子类型查询");
    }

    private void initMessageUser(String messageId,List<String> userIdList){
        if(ObjectUtils.isEmpty(userIdList)){
            return;
        }
        List<MessageUserEntity> userMessageList = new ArrayList<>();
        for(String userId : userIdList){
            MessageUserEntity entity = new MessageUserEntity();
            entity.setId(AppUtils.genIdStr());
            entity.setMessageId(messageId);
            entity.setUserId(userId);
            userMessageList.add(entity);
        }
        messageMapper.initMessageUser(userMessageList);
    }

    private String querySerialName(String companyId,Integer serialNo){
        String serialName = "";
        List<FeedAllocConfig> list = feedAllocConfigMapper.selectList(new QueryWrapper<FeedAllocConfig>().eq("company_id",companyId).eq("serial_no",serialNo));
        if(ObjectUtils.isNotEmpty(list)){
            serialName = list.get(0).getName();
        }
        return StringUtils.trimToEmpty(serialName);
    }

    private static Date getMessageQueryTime(Date userCreateTime){
        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.DATE,-180);
        Date date = calendar.getTime();
        if(null == userCreateTime || date.compareTo(userCreateTime) > 0){
            return date;
        }
        return userCreateTime;
    }

    private Date getOnePageTime(Integer pageIndex,List<Integer> typeList){
        Set<String> typeSet = new TreeSet<>();
        if(ObjectUtils.isNotEmpty(typeList)){
            for (Integer type : typeList){
                typeSet.add(String.valueOf(type));
            }
        }
        String userId = AppSessionUtils.getUserId();
        String id = userId + "_" + String.join("_",typeSet);
        MessageQueryTimeEntity timeEntity = messageQueryTimeMapper.selectById(id);
        Date onePageTime = null;
        if(null != timeEntity){
            onePageTime = timeEntity.getOnePageTime();
        }
        if(null != pageIndex && 1 == pageIndex){
            onePageTime = new Date();
            if(null == timeEntity){
                MessageQueryTimeEntity addEntity = new MessageQueryTimeEntity();
                addEntity.setId(id);
                addEntity.setOnePageTime(onePageTime);
                messageQueryTimeMapper.insert(addEntity);
            }else {
                MessageQueryTimeEntity updEntity = new MessageQueryTimeEntity();
                updEntity.setId(id);
                updEntity.setOnePageTime(onePageTime);
                messageQueryTimeMapper.updateById(updEntity);
            }
        }
        return onePageTime;
    }


}
